package fr.mywiki.business.structure;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import javax.ejb.FinderException;

import fr.mywiki.business.resources.ResourceManager;
import fr.mywiki.model.ejbAdapter.Value;


/**
 * Management of the tree functionalities.
 * 
 */
public class TreeManager {
	/* Tree types */
	/**
	 * Tree for single element selection. In particular the selection of a node
	 * unselects all the others.
	 */
	public static final int TYPE_SINGLE = 1;
	/**
	 * Tree for multi element selection. The only way to unselect a node is to
	 * click on it again.
	 */
	public static final int TYPE_MULTI = 3;
	
	public static final String PIX_TRANSPARENT_GIF_KEY = "tree.transparent";
	public static final String CLOSED_GIF_KEY = "tree.closed";
	
	/**
	 * Returns all the root nodes of the structure. TODO order & organize,
	 * eventually save in session. Add a way to use the profile of the user as a
	 * filter of the root nodes.
	 */
	public static List getTreeRootNodes() throws RemoteException, FinderException {
		return new ArrayList(StructureManager.getOrderedRootNodes());
	}
	
	/**
	 * Builds the tree representation from the collection of root nodes.
	 * 
	 * @param nodes
	 *          a <code>Collection</code> of <code>StructureLite</code>
	 *          objects.
	 * @param locale the current locale.
	 * @param type the type of the tree : TYPE_SINGLE or TYPE_MULTI
	 * @return a String representation of the whole tree. Here, a Javascript code
	 *         which displays the tree.
	 */
	public static String buildTree(Collection nodes, Locale locale, int type)
			throws RemoteException, FinderException {
		if (TYPE_MULTI == type)
			return buildJSTreeMulti(nodes, locale);
		return buildJSTreeSingle(nodes, locale);
	}

	/**
	 * Builds the multi-tree representation from the collection of root nodes and the selected ones.
	 * 
	 * @param nodes a <code>Collection</code> of <code>StructureLite</code>
	 *          objects.
	 * @param locale the current locale.
	 * @param selected a <code>ArrayList</code> of <code>StructureLite</code>
	 *          objects, the already selected nodes.
	 * @return a String representation of the whole tree. Here, a Javascript code
	 *         which displays the tree.
	 */
	public static String buildTree(Collection nodes, Locale locale,
			ArrayList selected) throws RemoteException, FinderException {
		return buildJSTreeMulti(nodes, locale, selected);
	}
	
	/**
	 * Builds the Javascript code which builds the tree which starts with the root
	 * nodes given in parameter. The tree is a single selection one.
	 * 
	 * @param nodes a <code>Collection</code> of <code>StructureLite</code>
	 *          objects
	 * @param locale the current locale
	 * @return a String object representing Javascript code.
	 */
	private static String buildJSTreeSingle(Collection nodes, Locale locale) throws RemoteException, FinderException {
		StringBuffer buffer = new StringBuffer();
		Iterator itNodes = nodes.iterator();
		while(itNodes.hasNext()) {
			StructureLite node = (StructureLite) itNodes.next();

			String id = node.getId().toString();
			String closed = ResourceManager.getImage(CLOSED_GIF_KEY,locale);
			String transparent = ResourceManager.getImage(PIX_TRANSPARENT_GIF_KEY,locale);
			
			ArrayList children;
			if (StructureManager.hasChildren(node))
				children = new ArrayList(StructureManager.getOrderedChildren(node));
			else
				children = null;
			if (children == null || children.isEmpty()) {
				buffer
					.append("<a name=\"")
					.append(id)
					.append("\"></a><span class=\"trigger\" onClick=\"display('")
					.append(id)
					.append("');swapText('")
					.append(id)
					.append("')\"><img src=\"")
					.append(transparent)
					.append("\" border=\"0\" width=\"15\"/><span class=\"unselect\" id=\"text")
					.append(id)
					.append("\">")
					.append(node.getName())
					.append("</span><br></span>");
			} else {
				buffer
					.append("<span class=\"trigger\"  onClick=\"display('")
					.append(id)
					.append("');swapText('")
					.append(id)
					.append("')\"><img src=\"")
					.append(closed)
					.append("\" border=\"0\" id=\"folder")
					.append(id)
					.append("\" onClick=\"showBranch('branch")
					.append(id)
					.append("');swapImage('folder")
					.append(id)
					.append("');\"/><span class=\"unselect\" id=\"text")
					.append(id)
					.append("\">")
					.append(node.getName())
					.append("</span><br></span><a name=\"")
					.append(id)
					.append("\"></a><span class=\"branch\" id=\"branch")
					.append(id)
					.append("\">")
					.append(buildJSTreeSingle(children,locale))
					.append("</span>");
			}
		}
		return buffer.toString();
	}
	
	/**
	 * Builds the Javascript code which builds the tree which starts with the root
	 * nodes given in parameter. The tree is a multiple selection one.
	 * 
	 * @param nodes
	 *          a <code>Collection</code> of <code>StructureLite</code>
	 *          objects, the children of the calling node (only one level).
	 * @param locale
	 *          the current locale
	 * @return a String object representing Javascript code.
	 */
	private static String buildJSTreeMulti(Collection nodes, Locale locale) throws RemoteException, FinderException {
		return buildJSTreeMulti(nodes,locale,new ArrayList());
	}
	
	/**
	 * Builds the Javascript code which builds the tree which starts with the root
	 * nodes given in parameter. The tree is a multiple selection one.
	 * 
	 * @param nodes
	 *          a <code>Collection</code> of <code>StructureLite</code>
	 *          objects, the children of the calling node (only one level).
	 * @param locale
	 *          the current locale
	 * @param selected
	 *          a <code>ArrayList</code> of <code>StructureLite</code>
	 *          objects, being the nodes that have to be already selected.
	 * @return a String object representing Javascript code.
	 */
	private static String buildJSTreeMulti(Collection nodes, Locale locale, ArrayList selected) throws RemoteException, FinderException {
		StringBuffer buffer = new StringBuffer();
		Iterator itNodes = nodes.iterator();
		while(itNodes.hasNext()) {
			StructureLite node = (StructureLite) itNodes.next();
			
			String id = node.getId().toString();
			String closed = ResourceManager.getImage(CLOSED_GIF_KEY,locale);
			String transparent = ResourceManager.getImage(PIX_TRANSPARENT_GIF_KEY,locale);
			
			ArrayList children;
			if (StructureManager.hasChildren(node))
				children = new ArrayList(StructureManager.getOrderedChildren(node));
			else
				children = null;
			if (children == null || children.isEmpty()) {
				buffer
						.append("<a name=\"")
						.append(id)
						.append("\"></a><span class=\"trigger\" onClick=\"display('")
						.append(id)
						.append("');swapText('")
						.append(id)
						.append("')\">")
						.append("<img src=\"")
						.append(transparent)
						.append("\" border=\"0\" width=\"15\"/><span class=\"")
						.append(selected.contains(node)?"select":"unselect")
						.append("\" id=\"text")
						.append(id)
						.append("\">")
						.append(node.getName())
						.append("</span><br></span>");
			} else {
				buffer
						.append("<span class=\"trigger\" >")
						.append("<img src=\""+closed+"\" border=\"0\" id=\"folder")
						.append(id)
						.append("\" onClick=\"showBranch('branch")
						.append(id)
						.append("');swapImage('folder")
						.append(id)
						.append("');\"/>")
						.append("<span class=\"")
						.append(selected.contains(node)?"select":"unselect")
						.append("\" id=\"text")
						.append(id)
						.append("\" onClick=\"swapText('")
						.append(id)
						.append("')\">")
						.append(node.getName())
						.append("</span><br>")
						.append("</span>")
						.append("<a name=\"")
						.append(id)
						.append("\"></a>")
						.append("<span class=\"branch\" id=\"branch")
						.append(id)
						.append("\">")
						.append(buildJSTreeMulti(children,locale,selected))
						.append("</span>");
			}
		}
		return buffer.toString();
	}
	
	/**
	 * Generates the Html code which executes the Javascript code which will open
	 * the tree.
	 * 
	 * @param structure
	 *          the current selected structure.
	 * @return a String object, representing html code
	 */
	public static String getExpandCodeJS(StructureLite structure) throws RemoteException, FinderException {
		StringBuffer buffer = new StringBuffer();
		buffer.append("showBranch('root');swapImage('rootimg');");

		// expand tree
		if (structure != null) {
			Collection expanded = getExpandedElements(structure);

			Iterator itStruct = expanded.iterator();
			while (itStruct.hasNext()) {
				Value struct = (StructureLite) itStruct.next();
				String idStruct = struct.getId().toString();

				buffer.append("branchToOpen = document.getElementById('branch");
				buffer.append(idStruct).append("');");
				buffer.append("if ( branchToOpen != null ) {");
				buffer.append("showBranch('branch");
				buffer.append(idStruct).append("');swapImage('folder");
				buffer.append(idStruct).append("');}");
			}

			Collection children = StructureManager.getChildren(structure);
			if (!children.isEmpty()) {
				buffer.append("showBranch('branch");
				buffer.append(structure.getId()).append("');swapImage('folder");
				buffer.append(structure.getId()).append("');");
			}

			buffer.append("swapText('");
			buffer.append(structure.getId()).append("');");
		}
		return buffer.toString();
	}
	
	/**
	 * Returns the elements to be expanded
	 * 
	 * @param structure
	 *          a <code>StructureLite</code> object which represents the
	 *          structure to make visible.
	 * @return a <code>Collection</code> of nodes to expand.
	 */
	public static Collection getExpandedElements(StructureLite structure) {
		List expanded = new ArrayList();
		try {
			StructureLite parent = StructureManager.getParent(structure);
			while (parent != null) {
				expanded.add(0, parent);
				parent = StructureManager.getParent(parent);
			}
		} catch (Exception e) {
			System.err.println("Cannot getExpandedElements : " + e.getMessage());
			e.printStackTrace();
		}
		return expanded;
	}
}
